//
// DotNetNuke - http://www.dotnetnuke.com
// Copyright (c) 2002-2010
// by Perpetual Motion Interactive Systems Inc. ( http://www.perpetualmotion.ca )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions 
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
// DEALINGS IN THE SOFTWARE.
//

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;
using System.Xml;
using DotNetNuke.Common.Utilities;
using DotNetNuke.ComponentModel;
using DotNetNuke.Entities.Host;
using DotNetNuke.Services.Log.EventLog.DBLoggingProvider.Data;
namespace DotNetNuke.Services.Log.EventLog.DBLoggingProvider
{
	public class DBLoggingProvider : DotNetNuke.Services.Log.EventLog.LoggingProvider
	{
		private static IList<LogQueueItem> LogQueue = new List<LogQueueItem>();
		private static ReaderWriterLock lockNotif = new ReaderWriterLock();
		private static ReaderWriterLock lockQueueLog = new ReaderWriterLock();
		private const int ReaderLockTimeout = 10000;
		private const int WriterLockTimeout = 10000;
		public DBLoggingProvider()
		{
			if (DataProvider.Instance() == null) {
				DataProvider objProvider = null;
				string defaultprovider = DotNetNuke.Data.DataProvider.Instance().DefaultProviderName;
				string dataProviderNamespace = "DotNetNuke.Services.Log.EventLog.DBLoggingProvider.Data";
				if (defaultprovider == "SqlDataProvider") {
					objProvider = new SqlDataProvider();
				} else {
					string providerType = dataProviderNamespace + "." + defaultprovider;
					objProvider = (DataProvider)Framework.Reflection.CreateObject(providerType, providerType, true);
				}
				ComponentFactory.RegisterComponentInstance<DataProvider>(objProvider);
			}
		}
		private Hashtable FillLogTypeConfigInfoByKey(ArrayList arr)
		{
			Hashtable ht = new Hashtable();
			int i;
			for (i = 0; i <= arr.Count - 1; i++) {
				LogTypeConfigInfo obj;
				obj = (LogTypeConfigInfo)arr[i];
				if (String.IsNullOrEmpty(obj.LogTypeKey))
					obj.LogTypeKey = "*";
				if (String.IsNullOrEmpty(obj.LogTypePortalID))
					obj.LogTypePortalID = "*";
				ht.Add(obj.LogTypeKey + "|" + obj.LogTypePortalID, obj);
			}
			DataCache.SetCache("GetLogTypeConfigInfoByKey", ht);
			return ht;
		}
		private LogTypeConfigInfo GetLogTypeConfigInfoByKey(string LogTypeKey, string LogTypePortalID)
		{
			Hashtable ht;
			ht = (Hashtable)DataCache.GetCache("GetLogTypeConfigInfoByKey");
			if (ht == null) {
				ht = FillLogTypeConfigInfoByKey(GetLogTypeConfigInfo());
			}
			LogTypeConfigInfo objLogTypeConfigInfo;
			objLogTypeConfigInfo = (LogTypeConfigInfo)ht[LogTypeKey + "|" + LogTypePortalID];
			if (objLogTypeConfigInfo == null) {
				objLogTypeConfigInfo = (LogTypeConfigInfo)ht["*|" + LogTypePortalID];
				if (objLogTypeConfigInfo == null) {
					objLogTypeConfigInfo = (LogTypeConfigInfo)ht[LogTypeKey + "|*"];
					if (objLogTypeConfigInfo == null) {
						objLogTypeConfigInfo = (LogTypeConfigInfo)ht["*|*"];
					} else {
						return objLogTypeConfigInfo;
					}
				} else {
					return objLogTypeConfigInfo;
				}
			} else {
				return objLogTypeConfigInfo;
			}
			return objLogTypeConfigInfo;
		}
		private LogInfo FillLogInfo(IDataReader dr)
		{
			LogInfo obj = new LogInfo();
			try {
				string LogGUID;
				LogGUID = Convert.ToString(dr["LogGUID"]);
				obj.LogCreateDate = Convert.ToDateTime(dr["LogCreateDate"]);
				obj.LogGUID = Convert.ToString(dr["LogGUID"]);
				if (dr["LogPortalID"] != DBNull.Value) {
					obj.LogPortalID = Convert.ToInt32(dr["LogPortalID"]);
				}
				if (dr["LogPortalName"] != DBNull.Value)
				{
					obj.LogPortalName = Convert.ToString(dr["LogPortalName"]);
				}
				if (dr["LogServerName"] != DBNull.Value)
				{
					obj.LogServerName = Convert.ToString(dr["LogServerName"]);
				}
				if (dr["LogUserID"] != DBNull.Value)
				{
					obj.LogUserID = Convert.ToInt32(dr["LogUserID"]);
				}
				obj.LogTypeKey = Convert.ToString(dr["LogTypeKey"]);
				obj.LogUserName = Convert.ToString(dr["LogUserName"]);
				obj.LogConfigID = Convert.ToString(dr["LogConfigID"]);
				obj.LogProperties.Deserialize(Convert.ToString(dr["LogProperties"]));
			} catch {
			}
			return obj;
		}
		private void WriteLog(LogQueueItem objLogQueueItem)
		{
			LogTypeConfigInfo objLogTypeConfigInfo = null;
			try {
				objLogTypeConfigInfo = objLogQueueItem.LogTypeConfigInfo;
				if (objLogTypeConfigInfo != null) {
					LogInfo objLogInfo = objLogQueueItem.LogInfo;
					string LogProperties = objLogInfo.LogProperties.Serialize();
					DataProvider.Instance().AddLog(objLogInfo.LogGUID, objLogInfo.LogTypeKey, objLogInfo.LogUserID, objLogInfo.LogUserName, objLogInfo.LogPortalID, objLogInfo.LogPortalName, objLogInfo.LogCreateDate, objLogInfo.LogServerName, LogProperties, Convert.ToInt32(objLogInfo.LogConfigID));
					if (objLogTypeConfigInfo.EmailNotificationIsActive == true) {
						lockNotif.AcquireWriterLock(ReaderLockTimeout);
						try {
							if (objLogTypeConfigInfo.NotificationThreshold == 0) {
								string str = objLogQueueItem.LogInfo.Serialize();
								//Mail.Mail.SendMail(objLogTypeConfigInfo.MailFromAddress, objLogTypeConfigInfo.MailToAddress, "", "Event Notification", str, "", "", "", "", "", "")

                                Mail.Mail.SendEmail(objLogTypeConfigInfo.MailFromAddress, objLogTypeConfigInfo.MailToAddress, "Event Notification", str);
							} else if (objLogTypeConfigInfo.LogTypeKey != "LOG_NOTIFICATION_FAILURE") {
							}
						} finally {
							lockNotif.ReleaseWriterLock();
						}
					}
				}
				if (objLogTypeConfigInfo.EmailNotificationIsActive == true) {
					if (objLogTypeConfigInfo.NotificationThreshold == 0) {
					} else if (objLogTypeConfigInfo.LogTypeKey != "LOG_NOTIFICATION_FAILURE") {
					}
				}
			} 
            catch(SqlException exc)
            {
                if ((HttpContext.Current != null))
                {
                    HttpResponse response = HttpContext.Current.Response;
                    HtmlUtils.WriteHeader(response, "SQL Exception");

                    string strMessage = DotNetNuke.Common.Utilities.SqlUtils.TranslateSQLException(exc);
                    HtmlUtils.WriteError(response, objLogTypeConfigInfo.LogFileNameWithPath, strMessage);

                    HtmlUtils.WriteFooter(response);
                    response.End();
                }

            }
			catch (Exception exc) {
				if (HttpContext.Current != null) {
					HttpResponse response = HttpContext.Current.Response;
					HtmlUtils.WriteHeader(response, "Unhandled Error");
					string strMessage = exc.Message;
					HtmlUtils.WriteError(response, objLogTypeConfigInfo.LogFileNameWithPath, strMessage);
					HtmlUtils.WriteFooter(response);
					response.End();
				}
			}
		}
		public override void AddLog(LogInfo objLogInfo)
		{
			string ConfigPortalID;
			if (objLogInfo.LogPortalID != Null.NullInteger) {
				ConfigPortalID = objLogInfo.LogPortalID.ToString();
			} else {
				ConfigPortalID = "*";
			}
			LogTypeConfigInfo objLogTypeConfigInfo;
			objLogTypeConfigInfo = GetLogTypeConfigInfoByKey(objLogInfo.LogTypeKey, ConfigPortalID);
			if (objLogTypeConfigInfo.LoggingIsActive == false) {
				return;
			}
			objLogInfo.LogConfigID = objLogTypeConfigInfo.ID;
			LogQueueItem objLogQueueItem = new LogQueueItem();
			objLogQueueItem.LogInfo = objLogInfo;
			objLogQueueItem.LogTypeConfigInfo = objLogTypeConfigInfo;
			Scheduling.SchedulingProvider scheduler = Scheduling.SchedulingProvider.Instance();
			if (objLogInfo.BypassBuffering || Scheduling.SchedulingProvider.Enabled == false || scheduler.GetScheduleStatus() == Scheduling.ScheduleStatus.STOPPED || !Host.EventLogBuffer)
			{
				WriteLog(objLogQueueItem);
			} else {
				LogQueue.Add(objLogQueueItem);
			}
		}
		public override void AddLogType(string LogTypeKey, string LogTypeFriendlyName, string LogTypeDescription, string LogTypeCSSClass, string LogTypeOwner)
		{
			DataProvider.Instance().AddLogType(LogTypeKey, LogTypeFriendlyName, LogTypeDescription, LogTypeCSSClass, LogTypeOwner);
		}
		public override void AddLogTypeConfigInfo(string ID, bool LoggingIsActive, string LogTypeKey, string LogTypePortalID, string KeepMostRecent, string LogFileName, bool EmailNotificationIsActive, string Threshold, string ThresholdTime, string ThresholdTimeType,
		string MailFromAddress, string MailToAddress)
		{
			int intThreshold = -1;
			int intThresholdTime = -1;
			int intThresholdTimeType = -1;
			int intKeepMostRecent = -1;
			if (Regex.IsMatch(Threshold,"^\\d+$"))
				intThreshold = Convert.ToInt32(Threshold);
			if (Regex.IsMatch(ThresholdTime,"^\\d+$"))
				intThresholdTime = Convert.ToInt32(ThresholdTime);
			if (Regex.IsMatch(ThresholdTimeType,"^\\d+$"))
				intThresholdTimeType = Convert.ToInt32(ThresholdTimeType);
			if (Regex.IsMatch(KeepMostRecent,"^\\d+$"))
				intKeepMostRecent = Convert.ToInt32(KeepMostRecent);
			DataProvider.Instance().AddLogTypeConfigInfo(LoggingIsActive, LogTypeKey, LogTypePortalID, intKeepMostRecent, EmailNotificationIsActive, intThreshold, intThresholdTime, intThresholdTimeType, MailFromAddress, MailToAddress);
			DataCache.RemoveCache("GetLogTypeConfigInfo");
			DataCache.RemoveCache("GetLogTypeConfigInfoByKey");
		}
		public override void ClearLog()
		{
			DataProvider.Instance().ClearLog();
		}
		public override void DeleteLog(LogInfo LogInfo)
		{
			DataProvider.Instance().DeleteLog(LogInfo.LogGUID);
		}
		public override void DeleteLogType(string LogTypeKey)
		{
			DataProvider.Instance().DeleteLogType(LogTypeKey);
		}
		public override void DeleteLogTypeConfigInfo(string ID)
		{
			DataProvider.Instance().DeleteLogTypeConfigInfo(ID);
			DataCache.RemoveCache("GetLogTypeConfigInfo");
			DataCache.RemoveCache("GetLogTypeConfigInfoByKey");
		}
		public override LogInfoArray GetLog(int PageSize, int PageIndex, ref int TotalRecords)
		{
			LogInfoArray objArr = new LogInfoArray();
			IDataReader dr = DataProvider.Instance().GetLog(PageSize, PageIndex);
			try {
				LogInfo objLogInfo;
				while (dr.Read()) {
					objLogInfo = FillLogInfo(dr);
					objArr.Add(objLogInfo);
				}
				dr.NextResult();
				while (dr.Read()) {
					TotalRecords = Convert.ToInt32(dr["TotalRecords"]);
				}
			} finally {
				CBO.CloseDataReader(dr, true);
			}
			return objArr;
		}
		public override LogInfoArray GetLog(string LogType, int PageSize, int PageIndex, ref int TotalRecords)
		{
			LogInfoArray objArr = new LogInfoArray();
			IDataReader dr = DataProvider.Instance().GetLog(LogType, PageSize, PageIndex);
			try {
				LogInfo objLogInfo;
				while (dr.Read()) {
					objLogInfo = FillLogInfo(dr);
					objArr.Add(objLogInfo);
				}
				dr.NextResult();
				while (dr.Read()) {
					TotalRecords = Convert.ToInt32(dr["TotalRecords"]);
				}
			} finally {
				CBO.CloseDataReader(dr, true);
			}
			return objArr;
		}
		public override LogInfoArray GetLog(int PortalID, int PageSize, int PageIndex, ref int TotalRecords)
		{
			if (PortalID == -1) {
				return GetLog();
			}
			LogInfoArray objArr = new LogInfoArray();
			IDataReader dr = DataProvider.Instance().GetLog(PortalID, PageSize, PageIndex);
			try {
				LogInfo objLogInfo;
				while (dr.Read()) {
					objLogInfo = FillLogInfo(dr);
					objArr.Add(objLogInfo);
				}
				dr.NextResult();
				while (dr.Read()) {
					TotalRecords = Convert.ToInt32(dr["TotalRecords"]);
				}
			} finally {
				CBO.CloseDataReader(dr, true);
			}
			return objArr;
		}
		public override LogInfoArray GetLog(int PortalID, string LogType, int PageSize, int PageIndex, ref int TotalRecords)
		{
			if (PortalID == -1) {
				return GetLog(LogType);
			}
			LogInfoArray objArr = new LogInfoArray();
			IDataReader dr = DataProvider.Instance().GetLog(PortalID, LogType, PageSize, PageIndex);
			try {
				LogInfo objLogInfo;
				while (dr.Read()) {
					objLogInfo = FillLogInfo(dr);
					objArr.Add(objLogInfo);
				}
				dr.NextResult();
				while (dr.Read()) {
					TotalRecords = Convert.ToInt32(dr["TotalRecords"]);
				}
			} finally {
				CBO.CloseDataReader(dr, true);
			}
			return objArr;
		}
		public override LogInfoArray GetLog()
		{
			LogInfoArray objArr = new LogInfoArray();
			IDataReader dr = DataProvider.Instance().GetLog();
			try {
				LogInfo objLogInfo;
				while (dr.Read()) {
					objLogInfo = FillLogInfo(dr);
					objArr.Add(objLogInfo);
				}
			} finally {
				CBO.CloseDataReader(dr, true);
			}
			return objArr;
		}
		public override LogInfoArray GetLog(string LogType)
		{
			LogInfoArray objArr = new LogInfoArray();
			IDataReader dr = DataProvider.Instance().GetLog(LogType);
			try {
				LogInfo objLogInfo;
				while (dr.Read()) {
					objLogInfo = FillLogInfo(dr);
					objArr.Add(objLogInfo);
				}
			} finally {
				CBO.CloseDataReader(dr, true);
			}
			return objArr;
		}
		public override LogInfoArray GetLog(int PortalID)
		{
			if (PortalID == -1) {
				return GetLog();
			}
			LogInfoArray objArr = new LogInfoArray();
			IDataReader dr = DataProvider.Instance().GetLog(PortalID);
			try {
				LogInfo objLogInfo;
				while (dr.Read()) {
					objLogInfo = FillLogInfo(dr);
					objArr.Add(objLogInfo);
				}
			} finally {
				CBO.CloseDataReader(dr, true);
			}
			return objArr;
		}
		public override LogInfoArray GetLog(int PortalID, string LogType)
		{
			if (PortalID == -1) {
				return GetLog(LogType);
			}
			LogInfoArray objArr = new LogInfoArray();
			IDataReader dr = DataProvider.Instance().GetLog(PortalID, LogType);
			try {
				LogInfo objLogInfo;
				while (dr.Read()) {
					objLogInfo = FillLogInfo(dr);
					objArr.Add(objLogInfo);
				}
			} finally {
				CBO.CloseDataReader(dr, true);
			}
			return objArr;
		}
		public override ArrayList GetLogTypeConfigInfo()
		{
			ArrayList arr;
			arr = (ArrayList)DataCache.GetCache("GetLogTypeConfigInfo");
			if (arr == null) {
				IDataReader dr = null;
				try {
					dr = DataProvider.Instance().GetLogTypeConfigInfo();
					arr = CBO.FillCollection(dr, typeof(LogTypeConfigInfo));
					DataCache.SetCache("GetLogTypeConfigInfo", arr);
					FillLogTypeConfigInfoByKey(arr);
				} finally {
					if (dr == null) {
						arr = new ArrayList();
					} else {
						CBO.CloseDataReader(dr, true);
					}
				}
			}
			return arr;
		}
		public override LogTypeConfigInfo GetLogTypeConfigInfoByID(string ID)
		{
			return (LogTypeConfigInfo)CBO.FillObject(DataProvider.Instance().GetLogTypeConfigInfoByID(Convert.ToInt32(ID)), typeof(LogTypeConfigInfo));
		}
		public override ArrayList GetLogTypeInfo()
		{
			return CBO.FillCollection(DataProvider.Instance().GetLogTypeInfo(), typeof(LogTypeInfo));
		}
		public override object GetSingleLog(LogInfo LogInfo, LoggingProvider.ReturnType objReturnType)
		{
			IDataReader dr = DataProvider.Instance().GetSingleLog(LogInfo.LogGUID);
			LogInfo obj = null;
			try {
				if (dr != null) {
					dr.Read();
					obj = FillLogInfo(dr);
				}
			} finally {
				CBO.CloseDataReader(dr, true);
			}
			if (objReturnType == LoggingProvider.ReturnType.LogInfoObjects) {
				return obj;
			} else {
				XmlDocument xmlDoc = new XmlDocument();
				xmlDoc.LoadXml(obj.Serialize());
				return (XmlNode)xmlDoc.DocumentElement;
			}
		}
		public override bool LoggingIsEnabled(string LogType, int PortalID)
		{
			string ConfigPortalID = PortalID.ToString();
			if (PortalID == -1) {
				ConfigPortalID = "*";
			}
			LogTypeConfigInfo obj;
			obj = GetLogTypeConfigInfoByKey(LogType, ConfigPortalID);
			if (obj == null) {
				return false;
			}
			return obj.LoggingIsActive;
		}
		public override void PurgeLogBuffer()
		{
			lockQueueLog.AcquireWriterLock(WriterLockTimeout);
			try {
				for (int i = LogQueue.Count - 1; i >= 0; i += -1) {
					LogQueueItem logQueueItem = LogQueue[i];
					if (logQueueItem != null) {
						WriteLog(logQueueItem);
						LogQueue.Remove(logQueueItem);
					}
				}
			} finally {
				lockQueueLog.ReleaseWriterLock();
			}
			DataProvider.Instance().PurgeLog();
		}
		public override void SendLogNotifications()
		{
			ArrayList arrLogConfig;
			arrLogConfig = CBO.FillCollection(DataProvider.Instance().GetEventLogPendingNotifConfig(), typeof(LogTypeConfigInfo));
			int i;
			for (i = 0; i <= arrLogConfig.Count - 1; i++) {
				LogTypeConfigInfo objLogConfig;
				objLogConfig = (LogTypeConfigInfo)arrLogConfig[i];
				IDataReader dr = DataProvider.Instance().GetEventLogPendingNotif(Convert.ToInt32(objLogConfig.ID));
				string strLog = "";
				try {
					while (dr.Read()) {
						LogInfo objLogInfo = this.FillLogInfo(dr);
						strLog += objLogInfo.Serialize() + Environment.NewLine + Environment.NewLine;
					}
				} finally {
					CBO.CloseDataReader(dr, true);
				}
				dr = null;
				//Mail.Mail.SendMail(objLogConfig.MailFromAddress, objLogConfig.MailToAddress, "", "Event Notification", strLog, "", "", "", "", "", "")
                Mail.Mail.SendEmail(objLogConfig.MailFromAddress, objLogConfig.MailToAddress, "Event Notification", strLog);
				DataProvider.Instance().UpdateEventLogPendingNotif(Convert.ToInt32(objLogConfig.ID));
			}
		}
		public override bool SupportsEmailNotification()
		{
			return true;
		}
		public override bool SupportsInternalViewer()
		{
			return true;
		}
		public override bool SupportsSendToCoreTeam()
		{
			return false;
		}
		public override bool SupportsSendViaEmail()
		{
			return true;
		}
		public override void UpdateLogType(string LogTypeKey, string LogTypeFriendlyName, string LogTypeDescription, string LogTypeCSSClass, string LogTypeOwner)
		{
			DataProvider.Instance().UpdateLogType(LogTypeKey, LogTypeFriendlyName, LogTypeDescription, LogTypeCSSClass, LogTypeOwner);
		}
		public override void UpdateLogTypeConfigInfo(string ID, bool LoggingIsActive, string LogTypeKey, string LogTypePortalID, string KeepMostRecent, string LogFileName, bool EmailNotificationIsActive, string Threshold, string ThresholdTime, string ThresholdTimeType,
		string MailFromAddress, string MailToAddress)
		{
			int intThreshold = -1;
			int intThresholdTime = -1;
			int intThresholdTimeType = -1;
			int intKeepMostRecent = -1;
			if (Regex.IsMatch(Threshold,"^\\d+$"))
				intThreshold = Convert.ToInt32(Threshold);
			if (Regex.IsMatch(ThresholdTime,"^\\d+$"))
				intThresholdTime = Convert.ToInt32(ThresholdTime);
			if (Regex.IsMatch(ThresholdTimeType,"^\\d+$"))
				intThresholdTimeType = Convert.ToInt32(ThresholdTimeType);
			if (Regex.IsMatch(KeepMostRecent,"^\\d+$"))
				intKeepMostRecent = Convert.ToInt32(KeepMostRecent);
			DataProvider.Instance().UpdateLogTypeConfigInfo(ID, LoggingIsActive, LogTypeKey, LogTypePortalID, intKeepMostRecent, LogFileName, EmailNotificationIsActive, intThreshold, intThresholdTime, intThresholdTimeType,
			MailFromAddress, MailToAddress);
			DataCache.RemoveCache("GetLogTypeConfigInfo");
			DataCache.RemoveCache("GetLogTypeConfigInfoByKey");
		}
	}
}
